﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
using log4net;
using System.Configuration;
using Impinj.OctaneSdk;
using GS1.Utilitario;
using GS1.Entidad;

namespace ControlVehiculoRFIDPA
{
    public partial class ControlVehiculoRFIDPA : ServiceBase
    {

        #region --- Variables y Propiedades ---
        Timer timerServicioLectura = new Timer();
        private static readonly ILog log = LogManager.GetLogger(typeof(ControlVehiculoRFIDPA));

        // Create a collection to hold all the ImpinjReader instances.
        private ImpinjReader reader = null;
        private Status status = null;

        private List<Etiqueta> listaEntrada = new List<Etiqueta>();
        private List<Etiqueta> listaSalida = new List<Etiqueta>();

        private List<Etiqueta> listaEntradaTemporal = new List<Etiqueta>();
        private List<Etiqueta> listaSalidaTemporal = new List<Etiqueta>();

        private List<ControlVehiculoRFID> listaControlVehiculoRFID = new List<ControlVehiculoRFID>();

        private RFIDState estadoReader;
        private enum RFIDState
        {
            CONECTADO,
            DESCONECTADO
        }

        // Cabecera de identificacion de etiqueta
        private string IDENTIFICADOR_CAB_ETIQUETA = "0000";
        #endregion

        #region --- Constructor y Destructor ---

        public ControlVehiculoRFIDPA()
        {
            log4net.Config.XmlConfigurator.Configure();

            InitializeComponent();
        }
        #endregion

        #region --- Eventos del Servicio ---

        protected override void OnStart(string[] args)
        {
            try
            {
                log.Debug("------------------------------");
                log.Debug("Iniciando Servicio Lectura ... v20110603.1806");

                // Estableciendo parametros del timer del servicio
                this.IDENTIFICADOR_CAB_ETIQUETA = ConfigurationManager.AppSettings[Constantes.IDENTIFICADOR_CAB_ETIQUETA].desEncriptarDES(ConfigurationManager.AppSettings[Constantes.LLAVE_3DS]);
                timerServicioLectura.Interval = 1000 * Convert.ToInt16(ConfigurationManager.AppSettings[Constantes.SEGUNDOS_ENTRE_CADA_VERIFICACION]);
                timerServicioLectura.Enabled = true;
                timerServicioLectura.Start();

                // ------
                log.Debug("Iniciando conexion con Reader ...");
                this.estadoReader = RFIDState.DESCONECTADO;

                bool resultado = conectar();
                if (resultado)
                {
                    log.Debug("Se establecio conexion con Reader - " + ConfigurationManager.AppSettings[Constantes.IPREADER].desEncriptarDES(ConfigurationManager.AppSettings[Constantes.LLAVE_3DS]));

                    resultado = iniciarLectura();
                    if (resultado)
                    {
                        log.Debug("Se inicio la lectura del Reader");
                    }
                }

                // Estableciendo intervalor del timer de limpiezas

            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }
        }

        protected override void OnStop()
        {
            try
            {
                timerServicioLectura.Enabled = false;

                log.Debug("-------------------------------");
                log.Debug("Deteniendo Servicio Lectura ... v20110603.1806");

                // -------
                log.Debug("Deteniendo conexion con el  Reader ... ");
                detenerLectura();

                bool resultado = desconectar();
                if (resultado)
                {
                    log.Debug("Se finalizo conexion con Reader - " + ConfigurationManager.AppSettings[Constantes.IPREADER].desEncriptarDES(ConfigurationManager.AppSettings[Constantes.LLAVE_3DS]));
                }


            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }
        }

        #endregion

        #region --- Evento del Timer ---
        private void timerServicioLectura_Elapsed(object sender, ElapsedEventArgs e)
        {
            //Listas donde se almacena la etiqueta que se ha pasado al otro lado indicando que ya termino
            List<Etiqueta> listaEtiquetasTemporalEntrada = new List<Etiqueta>();
            List<Etiqueta> listaEtiquetasTemporalSalida = new List<Etiqueta>();

            try
            {
                //Se detiene el reloj
                timerServicioLectura.Stop();
                //Ejecutar las tareas por que el reloj se detuvo
                #region ---Barre Lista Entrada Temporal---
                foreach (Etiqueta etiquetaEntradaTemporal in this.listaEntradaTemporal)
                {
                    if (etiquetaEntradaTemporal.antena.Equals(Constantes.ANTENNA3.ToString()) |
                        etiquetaEntradaTemporal.antena.Equals(Constantes.ANTENNA4.ToString()))
                    {
                        //Valida si el último registro en la lista de entrada temporal ha pasado más de X minutos
                        if (validarTiempoLectura(etiquetaEntradaTemporal.fechaInicio))
                        {
                            //Se re establece que se trata del fin del movimiento del camión
                            etiquetaEntradaTemporal.tipo = Constantes.TIPOFIN;
                            //Se agrega a la lista 
                            this.listaEntrada.Add(etiquetaEntradaTemporal);
                            if (log.IsDebugEnabled)
                            {
                                log.Debug("Registro en Cola de Entrada:" + etiquetaEntradaTemporal.epc + " Antena: " + etiquetaEntradaTemporal.antena + " Tipo: " + etiquetaEntradaTemporal.tipo);
                            }
                            //Se agrega en la lista temporal que servirá para buscar en la lista original
                            listaEtiquetasTemporalEntrada.Add(etiquetaEntradaTemporal);

                        }
                    }
                }
                #endregion

                #region ---Barre Lista Salida Temporal---
                foreach (Etiqueta etiquetaSalidaTemporal in this.listaSalidaTemporal)
                {
                    if (etiquetaSalidaTemporal.antena.Equals(Constantes.ANTENNA1.ToString()) |
                        etiquetaSalidaTemporal.antena.Equals(Constantes.ANTENNA2.ToString()))
                    {
                        //Valida si el último registro en la lista de entrada temporal ha pasado más de X minutos
                        if (validarTiempoLectura(etiquetaSalidaTemporal.fechaInicio))
                        {
                            //Se re establece que se trata del fin del movimiento del camión
                            etiquetaSalidaTemporal.tipo = Constantes.TIPOFIN;
                            //Se agrega a la lista 
                            this.listaSalida.Add(etiquetaSalidaTemporal);
                            if (log.IsDebugEnabled)
                            {
                                log.Debug("Registro en Cola de Salida:" + etiquetaSalidaTemporal.epc + " Antena: " + etiquetaSalidaTemporal.antena + " Tipo: " + etiquetaSalidaTemporal.tipo);
                            }
                            //Se agrega en la lista temporal que servirá para buscar en la lista original
                            listaEtiquetasTemporalSalida.Add(etiquetaSalidaTemporal);
                        }
                    }
                }
                #endregion

                //obtiene el Numero de serie del reader
                FeatureSet features = this.reader.QueryFeatureSet();
                RequestMetada requestMetadata = new RequestMetada();
                requestMetadata.remoteHost = features.SerialNumber;



                //Busca en las listas a las etiquetas que están han cumplido con las condiciones y los borra de la lista
                #region ---Crea Vehiculo de la lista Entrada---
                foreach (Etiqueta etiquetaBuscar in this.listaEntradaTemporal)
                {
                    //Se crean variable Boolean para asegurar el cumplimiento del ciclo
                    Boolean bInicioAntena1_2 = false;
                    Boolean bFinAntena1_2 = false;
                    Boolean bInicioAntena3_4 = false;
                    Boolean bFinAntena3_4 = false;

                    //Se crea el objeto a enviar
                    ControlVehiculoRFID controlVehiculoRFID = new ControlVehiculoRFID();
                    controlVehiculoRFID.codigoEPC = etiquetaBuscar.epc;
                    controlVehiculoRFID.codigoDireccionVehiculo = Constantes.ENTRADA;
                    controlVehiculoRFID.descripcionPuerta = ConfigurationManager.AppSettings[Constantes.PUERTA].desEncriptarDES(ConfigurationManager.AppSettings[Constantes.LLAVE_3DS]).ToString();


                    foreach (Etiqueta etiqueta in this.listaEntrada)
                    {
                        if (etiqueta.epc.Equals(etiquetaBuscar.epc))
                        {
                            if (etiqueta.antena.Equals(Constantes.ANTENNA1.ToString()) |
                                etiqueta.antena.Equals(Constantes.ANTENNA2.ToString()))
                            {
                                if (etiqueta.tipo.Equals(Constantes.TIPOINICIO))
                                {
                                    controlVehiculoRFID.fechaInicioMovimiento = etiqueta.fechaInicio;
                                    bInicioAntena1_2 = true;
                                }
                                if (etiqueta.tipo.Equals(Constantes.TIPOFIN))
                                {
                                    bFinAntena1_2 = true;
                                }
                            }
                            if (etiqueta.antena.Equals(Constantes.ANTENNA3.ToString()) |
                                etiqueta.antena.Equals(Constantes.ANTENNA4.ToString()))
                            {
                                if (etiqueta.tipo.Equals(Constantes.TIPOINICIO))
                                {
                                    bInicioAntena3_4 = true;
                                }
                                if (etiqueta.tipo.Equals(Constantes.TIPOFIN))
                                {
                                    bFinAntena3_4 = true;
                                    controlVehiculoRFID.fechaFinalMovimiento = etiqueta.fechaInicio;
                                }
                            }
                        }
                    }
                    //termina loop de lista entrada
                    if (bInicioAntena1_2 &&
                        bFinAntena1_2 &&
                        bInicioAntena3_4 &&
                        bFinAntena3_4)
                    {
                        this.listaControlVehiculoRFID.Add(controlVehiculoRFID);
                        //limpieza de lista entrada
                        List<Etiqueta> listaEtiquetaAyuda = new List<Etiqueta>();
                        foreach (Etiqueta etiqueta in this.listaEntrada)
                        {
                            if (!etiqueta.epc.Equals(etiquetaBuscar.epc))
                            {
                                listaEtiquetaAyuda.Add(etiqueta);
                            }
                        }
                        this.listaEntrada = listaEtiquetaAyuda;
                    }
                }


                #endregion

                #region ---Crea Vehiculo de la lista Salida---
                foreach (Etiqueta etiquetaBuscar in this.listaSalidaTemporal)
                {
                    //Se crean variable Boolean para asegurar el cumplimiento del ciclo
                    Boolean bInicioAntena3_4 = false;
                    Boolean bFinAntena3_4 = false;
                    Boolean bInicioAntena1_2 = false;
                    Boolean bFinAntena1_2 = false;

                    //Se crea el objeto a enviar
                    ControlVehiculoRFID controlVehiculoRFID = new ControlVehiculoRFID();
                    controlVehiculoRFID.codigoEPC = etiquetaBuscar.epc;
                    controlVehiculoRFID.codigoDireccionVehiculo = Constantes.SALIDA;
                    controlVehiculoRFID.descripcionPuerta = ConfigurationManager.AppSettings[Constantes.PUERTA].desEncriptarDES(ConfigurationManager.AppSettings[Constantes.LLAVE_3DS]).ToString();

                    foreach (Etiqueta etiqueta in this.listaSalida)
                    {
                        if (etiqueta.epc.Equals(etiquetaBuscar.epc))
                        {

                            if (etiqueta.antena.Equals(Constantes.ANTENNA3.ToString()) ||
                                etiqueta.antena.Equals(Constantes.ANTENNA4.ToString()))
                            {
                                if (etiqueta.tipo.Equals(Constantes.TIPOINICIO))
                                {
                                    controlVehiculoRFID.fechaInicioMovimiento = etiqueta.fechaInicio;
                                    bInicioAntena3_4 = true;
                                }
                                if (etiqueta.tipo.Equals(Constantes.TIPOFIN))
                                {
                                    bFinAntena3_4 = true;
                                }
                            }
                            if (etiqueta.antena.Equals(Constantes.ANTENNA1.ToString()) ||
                                etiqueta.antena.Equals(Constantes.ANTENNA2.ToString()))
                            {
                                if (etiqueta.tipo.Equals(Constantes.TIPOINICIO))
                                {
                                    bInicioAntena1_2 = true;
                                }
                                if (etiqueta.tipo.Equals(Constantes.TIPOFIN))
                                {
                                    bFinAntena1_2 = true;
                                    controlVehiculoRFID.fechaFinalMovimiento = etiqueta.fechaInicio;
                                }
                            }
                        }
                    }
                    //termina loop de lista salida
                    if (bInicioAntena1_2 &&
                        bFinAntena1_2 &&
                        bInicioAntena3_4 &&
                        bFinAntena3_4)
                    {
                        this.listaControlVehiculoRFID.Add(controlVehiculoRFID);
                        //limpia lista salida
                        List<Etiqueta> listaEtiquetaAyuda = new List<Etiqueta>();
                        foreach (Etiqueta etiqueta in this.listaSalida)
                        {
                            if (!etiqueta.epc.Equals(etiquetaBuscar.epc))
                            {
                                listaEtiquetaAyuda.Add(etiqueta);
                            }
                        }
                        this.listaSalida = listaEtiquetaAyuda;
                    }

                }


                #endregion

                #region---enviaXML----
                foreach (ControlVehiculoRFID controlVehiculoRFID in this.listaControlVehiculoRFID)
                {
                    //Llama al objeto en java con la cadena en XML en post
                    string contenidoXML = string.Empty;
                    Operacion operacion = new Operacion();

                    operacion.controlVehiculoRFID = new ControlVehiculoRFID();
                    operacion.controlVehiculoRFID = controlVehiculoRFID;
                    operacion.requestMetadata = new RequestMetada();
                    operacion.requestMetadata = requestMetadata;


                    // Instanciando y ejecutando llamada al ServicioREST
                    ConexionREST conexionREST = new ConexionREST();
                    contenidoXML = conexionREST.ejecutarTrama(operacion);
                }

                //limpiar lista
                listaControlVehiculoRFID.Clear();
                #endregion

                #region---Limpia Lista Entrada---
                //Limpia de la lista si la lectura ha pasado más del tiempo indicado
                //Creo lista donde se va a poner nombres de las etiquetas a borrar
                List<Etiqueta> ListaAyudaEntrada = new List<Etiqueta>();
                //Revisa la lista Entrada Temporal y graba en la lista a borrar con los codigos EPC que no han sido vistos hace X tiempo
                foreach (Etiqueta etiqueta in this.listaEntradaTemporal)
                {
                    //Valido que no se haya visto en X tiempo
                    if (validarTiempoLimpiar(etiqueta.fechaInicio))
                    {
                        //Si no se ha visto en X tiempo, entonces se agrega a la lista
                        ListaAyudaEntrada.Add(etiqueta);
                    }
                }
                //Reviso la lista de etiquetas a remover de la lista
                foreach (Etiqueta etiquetaARemover in ListaAyudaEntrada)
                {
                    //Creo listas temporales, son dos para evitar confusiones
                    //Lista de ayuda para el registro de datos temporales
                    List<Etiqueta> listaEtiquetaTemporalAyuda = new List<Etiqueta>();
                    //Lista de ayuda para el registro de datos principales
                    List<Etiqueta> listaEtiquetaAyuda = new List<Etiqueta>();
                    //Reviso la lista de entrada temporal
                    foreach (Etiqueta etiqueta in this.listaEntradaTemporal)
                    {
                        //Si NO son iguales se graba, si esta en lista a remover no se considera
                        if (!etiquetaARemover.epc.Equals(etiqueta.epc))
                        {
                            //Se agrega en la lista temporal de ayuda
                            listaEtiquetaTemporalAyuda.Add(etiqueta);
                        }
                    }
                    //Se reemplaza la lista nueva por la lista antigua
                    this.listaEntradaTemporal = listaEtiquetaTemporalAyuda;
                    //Reviso la lista principal 
                    foreach (Etiqueta etiqueta in this.listaEntrada)
                    {
                        //Si NO son iguales se graba, si esta en lista a remover no se considera
                        if (!etiquetaARemover.epc.Equals(etiqueta.epc))
                        {
                            //Se agrega en la lista temporal de ayuda
                            listaEtiquetaAyuda.Add(etiqueta);
                        }
                    }
                    //Se reemplaza la lista nueva por la lista antigua
                    this.listaEntrada = listaEtiquetaAyuda;

                    //Enviar mensaje a Log de la etiqueta a remover (Indicando que no se ha registrado)
                }
                #endregion

                #region---Limpia Lista Salida---
                //Limpia de la lista si la lectura ha pasado más del tiempo indicado
                //Creo lista donde se va a poner nombres de las etiquetas a borrar
                List<Etiqueta> ListaAyudaSalida = new List<Etiqueta>();
                //Revisa la lista Salida Temporal y graba en la lista a borrar con los codigos EPC que no han sido vistos hace X tiempo
                foreach (Etiqueta etiqueta in this.listaSalidaTemporal)
                {
                    //Valido que no se haya visto en X tiempo
                    if (validarTiempoLimpiar(etiqueta.fechaInicio))
                    {
                        //Si no se ha visto en X tiempo, entonces se agrega a la lista
                        ListaAyudaSalida.Add(etiqueta);
                    }
                }
                //Reviso la lista de etiquetas a remover de la lista
                foreach (Etiqueta etiquetaARemover in ListaAyudaSalida)
                {
                    //Creo listas temporales, son dos para evitar confusiones
                    //Lista de ayuda para el registro de datos temporales
                    List<Etiqueta> listaEtiquetaTemporalAyuda = new List<Etiqueta>();
                    //Lista de ayuda para el registro de datos principales
                    List<Etiqueta> listaEtiquetaAyuda = new List<Etiqueta>();
                    //Reviso la lista de salida temporal
                    foreach (Etiqueta etiqueta in this.listaSalidaTemporal)
                    {
                        //Si NO son iguales se graba, si esta en lista a remover no se considera
                        if (!etiquetaARemover.epc.Equals(etiqueta.epc))
                        {
                            //Se agrega en la lista temporal de ayuda
                            listaEtiquetaTemporalAyuda.Add(etiqueta);
                        }
                    }
                    //Se reemplaza la lista nueva por la lista antigua
                    this.listaSalidaTemporal = listaEtiquetaTemporalAyuda;
                    //Reviso la lista principal 
                    foreach (Etiqueta etiqueta in this.listaSalida)
                    {
                        //Si NO son iguales se graba, si esta en lista a remover no se considera
                        if (!etiquetaARemover.epc.Equals(etiqueta.epc))
                        {
                            //Se agrega en la lista temporal de ayuda
                            listaEtiquetaAyuda.Add(etiqueta);
                        }
                    }
                    //Se reemplaza la lista nueva por la lista antigua
                    this.listaSalida = listaEtiquetaAyuda;
                }
                #endregion
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }
            finally
            {
                timerServicioLectura.Start();
            }
        }
        #endregion

        #region --- Procedimientos OctaneSDK ---
        private void inicializarReader()
        {
            this.reader = new ImpinjReader();
            // Capturado eventos de lectura de Tags
            this.reader.TagsReported += OnTagsReported;
        }

        private void finalizarReader()
        {
            this.reader.TagsReported -= OnTagsReported;
            this.reader = null;
        }

        private bool conectar()
        {
            bool resultado = false;
            try
            {
                inicializarReader();

                this.reader.Connect(ConfigurationManager.AppSettings[Constantes.IPREADER].desEncriptarDES(ConfigurationManager.AppSettings[Constantes.LLAVE_3DS]));

                this.reader.ApplyDefaultSettings();

                Settings settings = reader.QueryDefaultSettings();

                int indiceReaderMode = 0;
                indiceReaderMode = Convert.ToInt32(ConfigurationManager.AppSettings[Constantes.INDICE_READER_MODE]);

                // Estableciendo Reader Mode
                switch (indiceReaderMode)
                {
                    case 0://AutoSet Dense Reader
                        settings.ReaderMode = ReaderMode.AutoSetDenseReader;
                        break;
                    case 1://AutoSet Single Reader
                        settings.ReaderMode = ReaderMode.AutoSetSingleReader;
                        break;
                    case 2://Max Throughput
                        settings.ReaderMode = ReaderMode.MaxThroughput;
                        break;
                    case 3://Hybrid Mode
                        settings.ReaderMode = ReaderMode.Hybrid;
                        break;
                    case 4://Dense Reader (M=4)
                        settings.ReaderMode = ReaderMode.DenseReaderM4;
                        break;
                    case 5://Dense Reader (M=8)
                        settings.ReaderMode = ReaderMode.DenseReaderM8;
                        break;
                    case 6://MaxMiller
                        settings.ReaderMode = ReaderMode.MaxMiller;
                        break;
                }

                int indiceSearchMode = 0;
                indiceSearchMode = Convert.ToInt32(ConfigurationManager.AppSettings[Constantes.INDICE_SEARCH_MODE]);

                // Estableciendo Search Mode
                switch (indiceSearchMode)
                {
                    case 0://Dual Target
                        settings.SearchMode = SearchMode.DualTarget;
                        break;
                    case 1://Single Target Inventory
                        settings.SearchMode = SearchMode.SingleTarget;
                        break;
                    case 2://Single Target w/Supression
                        settings.SearchMode = SearchMode.TagFocus;
                        break;
                    case 3://Desconocido
                        settings.SearchMode = SearchMode.ReaderSelected;
                        break;
                }

                // Estableciendo Sesion
                settings.Session = Convert.ToUInt16(ConfigurationManager.AppSettings[Constantes.INDICE_SESSION]);

                settings.Antennas.DisableAll();

                settings.Antennas.GetAntenna(1).IsEnabled = ConfigurationManager.AppSettings[Constantes.ACTIVAR_ANTENA1].ToString().Equals(Constantes.SI);
                settings.Antennas.GetAntenna(9).IsEnabled = ConfigurationManager.AppSettings[Constantes.ACTIVAR_ANTENA2].ToString().Equals(Constantes.SI);
                settings.Antennas.GetAntenna(17).IsEnabled = ConfigurationManager.AppSettings[Constantes.ACTIVAR_ANTENA3].ToString().Equals(Constantes.SI);
                settings.Antennas.GetAntenna(25).IsEnabled = ConfigurationManager.AppSettings[Constantes.ACTIVAR_ANTENA4].ToString().Equals(Constantes.SI);

                if (settings.Antennas.GetAntenna(1).IsEnabled)
                {
                    settings.Antennas.GetAntenna(1).MaxRxSensitivity = (Constantes.SI == ConfigurationManager.AppSettings[Constantes.TODA_CAPACIDAD_ANTENA1]);
                    settings.Antennas.GetAntenna(1).MaxTransmitPower = (Constantes.SI == ConfigurationManager.AppSettings[Constantes.TODA_CAPACIDAD_ANTENA1]);
                    settings.Antennas.GetAntenna(1).TxPowerInDbm = Convert.ToDouble(ConfigurationManager.AppSettings[Constantes.POTENCIA_ANTENA1]);
                    settings.Antennas.GetAntenna(1).RxSensitivityInDbm = Convert.ToInt32(ConfigurationManager.AppSettings[Constantes.SENSIBILIDAD_ANTENA1]);
                }

                if (settings.Antennas.GetAntenna(9).IsEnabled)
                {
                    settings.Antennas.GetAntenna(9).MaxRxSensitivity = (Constantes.SI == ConfigurationManager.AppSettings[Constantes.TODA_CAPACIDAD_ANTENA2]);
                    settings.Antennas.GetAntenna(9).MaxTransmitPower = (Constantes.SI == ConfigurationManager.AppSettings[Constantes.TODA_CAPACIDAD_ANTENA2]);
                    settings.Antennas.GetAntenna(9).TxPowerInDbm = Convert.ToDouble(ConfigurationManager.AppSettings[Constantes.POTENCIA_ANTENA2]);
                    settings.Antennas.GetAntenna(9).RxSensitivityInDbm = Convert.ToInt32(ConfigurationManager.AppSettings[Constantes.SENSIBILIDAD_ANTENA2]);
                }

                if (settings.Antennas.GetAntenna(17).IsEnabled)
                {
                    settings.Antennas.GetAntenna(17).MaxRxSensitivity = (Constantes.SI == ConfigurationManager.AppSettings[Constantes.TODA_CAPACIDAD_ANTENA3]);
                    settings.Antennas.GetAntenna(17).MaxTransmitPower = (Constantes.SI == ConfigurationManager.AppSettings[Constantes.TODA_CAPACIDAD_ANTENA3]);
                    settings.Antennas.GetAntenna(17).TxPowerInDbm = Convert.ToDouble(ConfigurationManager.AppSettings[Constantes.POTENCIA_ANTENA3]);
                    settings.Antennas.GetAntenna(17).RxSensitivityInDbm = Convert.ToInt32(ConfigurationManager.AppSettings[Constantes.SENSIBILIDAD_ANTENA3]);
                }

                if (settings.Antennas.GetAntenna(25).IsEnabled)
                {
                    settings.Antennas.GetAntenna(25).MaxRxSensitivity = (Constantes.SI == ConfigurationManager.AppSettings[Constantes.TODA_CAPACIDAD_ANTENA4]);
                    settings.Antennas.GetAntenna(25).MaxTransmitPower = (Constantes.SI == ConfigurationManager.AppSettings[Constantes.TODA_CAPACIDAD_ANTENA4]);
                    settings.Antennas.GetAntenna(25).TxPowerInDbm = Convert.ToDouble(ConfigurationManager.AppSettings[Constantes.POTENCIA_ANTENA4]);
                    settings.Antennas.GetAntenna(25).RxSensitivityInDbm = Convert.ToInt32(ConfigurationManager.AppSettings[Constantes.SENSIBILIDAD_ANTENA4]);
                }

                settings.Report.IncludeAntennaPortNumber = true;
                settings.Report.IncludePeakRssi = true;
                settings.Report.IncludePhaseAngle = true;
                settings.Report.IncludeChannel = true;
                settings.Report.IncludeFirstSeenTime = true;
                settings.Report.IncludeLastSeenTime = true;
                settings.Report.IncludeSeenCount = true;
                settings.Report.IncludeFastId = true;
                settings.Report.Mode = ReportMode.Individual;

                // Estableciendo los nuevos parametros de configuracion
                this.reader.ApplySettings(settings);

                // Estableciendo identificador(MAC) del ReaderRFID
                //this.reader.ReaderIdentity = this.reader.QueryFeatureSet().ReaderIdentity;
                this.status = this.reader.QueryStatus();

                this.estadoReader = RFIDState.CONECTADO;

                resultado = true;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }

            return resultado;
        }

        private bool desconectar()
        {
            bool resultado = false;

            try
            {
                if (this.estadoReader == RFIDState.DESCONECTADO) { return true; }

                resultado = detenerLectura();

                if (resultado == false)
                {
                    this.reader.Disconnect();
                }

                finalizarReader();

                this.estadoReader = RFIDState.DESCONECTADO;

                resultado = true;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }

            return resultado;
        }

        private string obtenerInformacion()
        {
            StringBuilder cadenaInformacion = null;
            try
            {
                if (this.estadoReader == RFIDState.DESCONECTADO)
                {
                    log.Debug("Primero debe establecer conexion con el Reader");
                    return string.Empty;
                }

                cadenaInformacion = new StringBuilder();

                FeatureSet features = this.reader.QueryFeatureSet();

                cadenaInformacion.Append("Nombre del Modelo: " + features.ModelName);
                cadenaInformacion.Append(Environment.NewLine);
                cadenaInformacion.Append("Numero del Modelo: " + features.ModelNumber);
                cadenaInformacion.Append(Environment.NewLine);
                cadenaInformacion.Append("Numero de Serie: " + features.SerialNumber);
                cadenaInformacion.Append(Environment.NewLine);
                //cadenaInformacion.Append("Indetificación del Reader: " + this.status.ReaderIdentity.ToString());
                //cadenaInformacion.Append(Environment.NewLine);
                cadenaInformacion.Append("Version del Firmware: " + features.FirmwareVersion);
                cadenaInformacion.Append(Environment.NewLine);
                //cadenaInformacion.Append("Version del Octane software: " + features.SoftwareVersion);
                //cadenaInformacion.Append(Environment.NewLine);
                cadenaInformacion.Append("Cantidad de Antenas: " + features.AntennaCount);

                log.Debug(cadenaInformacion.ToString());
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }

            return cadenaInformacion.ToString();
        }

        private bool obtenerEstadoConexion()
        {
            bool conectado = false;
            try
            {
                Status status = this.reader.QueryStatus();
                conectado = status.IsConnected == true;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }

            return conectado;
        }

        private bool iniciarLectura()
        {
            bool resultado = false;
            try
            {
                if (this.estadoReader == RFIDState.DESCONECTADO) { return resultado; }

                if (!this.reader.QueryStatus().IsSingulating)
                {
                    this.reader.Start();
                }

                resultado = true;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }

            return resultado;
        }

        private bool detenerLectura()
        {
            bool resultado = false;
            try
            {
                if (this.estadoReader == RFIDState.DESCONECTADO)
                {
                    log.Debug("Primero debe establecer conexion con el Reader");
                    return resultado;
                }

                if (this.reader.QueryStatus().IsSingulating)
                {
                    this.reader.Stop();
                }

                resultado = true;

            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }

            return resultado;
        }

        #endregion

        #region --- Eventos del Reader ---
        private void OnTagsReported(ImpinjReader sender, TagReport report)
        {
            // This event handler is called asynchronously when tag reports are available.
            if (this.estadoReader == RFIDState.DESCONECTADO) { return; }

            try
            {
                // Validar si hay tag leidos
                if (report.Tags.Count == 0) { return; }

                // Validar si esta activo el comando de Lectura de Tag
                if (!ConfigurationManager.AppSettings[Constantes.ACTIVAR_COMANDO_LEC].ToString().Equals(Constantes.SI))
                { return; }

                // Loop por cada etiqueta que lea del report.
                foreach (Tag tag in report)
                {
                    // Validar que sea una etiqueta con la estructura de Hermes
                    if (!esEtiquetaValida(tag.Epc.ToString())) { return; }
                    //Registra Etiqueta
                    Etiqueta etiqueta = new Etiqueta();
                    etiqueta.epc = tag.Epc.ToString();
                    etiqueta.fechaInicio = DateTime.Now;//Es la dia y hora en que se lee la etiqueta en ese momento
                    etiqueta.fechaFinal = tag.LastSeenTime.LocalDateTime;
                    etiqueta.antena = tag.AntennaPortNumber.ToString();
                    etiqueta.tipo = string.Empty;

                    //La dirección se toma a partir de la lectura de las antenas
                    //Si va de la antena 1/2 a la antena 3/4 entonces es ENTRADA
                    //Si va de la antena 3/4 a la antena 1/2 entonces es SALIDA
                    #region ----IniciaConAntena1/2-----
                    if (tag.AntennaPortNumber.Equals(Constantes.ANTENNA1) |
                        tag.AntennaPortNumber.Equals(Constantes.ANTENNA2))
                    {
                        //Variable que indica que encontró la etiqueta en la lista
                        Boolean bEncontroListaEntrada = false;
                        foreach (Etiqueta etiquetaEntrada in this.listaEntrada)
                        {
                            //Pregunta si la etiqueta existe en listaEntrada
                            if (etiquetaEntrada.epc.Equals(etiqueta.epc))
                            {
                                bEncontroListaEntrada = true;
                                break;
                            }
                        }
                        //Si encontro la etiqueta en la lista, entonces actualiza sus datos en la lista entrada temporal
                        if (bEncontroListaEntrada)
                            this.listaEntradaTemporal = registroTemporal(etiqueta, this.listaEntradaTemporal, Constantes.TIPOFIN);
                        //Si NO existe en listaEntrada, busca etiqueta en listaSalida
                        else
                        {
                            Boolean bEncontroListaSalida = false;
                            Boolean bEncontroListaSalidaMismaAntena = false;
                            foreach (Etiqueta etiquetaSalida in this.listaSalida)
                            {
                                //Pregunta si la etiqueta existe en listaSalida
                                if (etiquetaSalida.epc.Equals(etiqueta.epc))
                                {
                                    //Pregunta si la antena que lo encontró es 3/4 y si es regitro de Inicio
                                    if (etiquetaSalida.tipo.Equals(Constantes.TIPOINICIO))
                                        if (etiquetaSalida.antena.Equals(Constantes.ANTENNA3.ToString()) |
                                          etiquetaSalida.antena.Equals(Constantes.ANTENNA4.ToString()))
                                        {
                                            //Registra que si lo encontró
                                            bEncontroListaSalida = true;
                                        }
                                    //Pregunta si la antena que lo encontró es 1/2
                                    if (etiquetaSalida.antena.Equals(Constantes.ANTENNA1.ToString()) |
                                        etiquetaSalida.antena.Equals(Constantes.ANTENNA2.ToString()))
                                    {
                                        bEncontroListaSalidaMismaAntena = true;
                                    }
                                }
                            }
                            //Encontró el Inicio de la lectura en la cola de salida de la antena 3/4
                            if (bEncontroListaSalida)
                            {
                                //Encontró al menos un registro en la lista de salida con la antena 1/2
                                if (bEncontroListaSalidaMismaAntena)
                                {
                                    //Como encontró un registro, 
                                    this.listaSalidaTemporal = registroTemporal(etiqueta, this.listaSalidaTemporal, Constantes.TIPOFIN);
                                }
                                //NO encontró ningún registro en la lista de salida sobre la antena 1/2
                                else
                                {
                                    //Se recupera la última etiqueta leída de listaSalidaTemporal
                                    foreach (Etiqueta etiquetaAMover in this.listaSalidaTemporal)
                                    {
                                        //Solo se debe validar que sea de la antena 3/4 porque el registro siempre es el último
                                        if (etiquetaAMover.epc.Equals(etiqueta.epc) &&
                                            (etiquetaAMover.antena.Equals(Constantes.ANTENNA3.ToString()) |
                                             etiquetaAMover.antena.Equals(Constantes.ANTENNA4.ToString())))
                                        {
                                            //Crea los datos de la etiqueta que se va a mover en una variable en memoria aparte
                                            Etiqueta etiquetaTemporal = new Etiqueta();
                                            etiquetaTemporal.antena = etiquetaAMover.antena;
                                            etiquetaTemporal.epc = etiquetaAMover.epc;
                                            etiquetaTemporal.fechaInicio = etiquetaAMover.fechaInicio;
                                            etiquetaTemporal.fechaFinal = etiquetaAMover.fechaFinal;
                                            etiquetaTemporal.tipo = Constantes.TIPOFIN;

                                            //Se graban la etiqueta temporal en Lista Salida
                                            this.listaSalida.Add(etiquetaTemporal);
                                            if (log.IsDebugEnabled)
                                            {
                                                log.Debug("Registro en Cola de Salida:" + etiquetaTemporal.epc + " Antena: " + etiquetaTemporal.antena + " Tipo: " + etiquetaTemporal.tipo);
                                            }
                                            //Se retira la etiqueta de la lista Salida Temporal
                                            this.listaSalidaTemporal.Remove(etiquetaAMover);
                                            //Sale de la lista
                                            break;
                                        }
                                    }
                                    //Graba etiqueta en lista Salida con Antena 1/2 pero con indicador de Inicio
                                    etiqueta.tipo = Constantes.TIPOINICIO;
                                    this.listaSalida.Add(etiqueta);
                                    if (log.IsDebugEnabled)
                                    {
                                        log.Debug("Registro en Cola de Salida:" + etiqueta.epc + " Antena: " + etiqueta.antena + " Tipo: " + etiqueta.tipo);
                                    }
                                }
                            }
                            //NO Encontró registro en la lista de Salida
                            else
                            {
                                //Se agrega el indicador que es el primer registro y se graba como inicio
                                etiqueta.tipo = Constantes.TIPOINICIO;
                                //Se agrega en la LISTA ENTRADA
                                this.listaEntrada.Add(etiqueta);
                                if (log.IsDebugEnabled)
                                {
                                    log.Debug("Registro en Cola de Entrada:" + etiqueta.epc + " Antena: " + etiqueta.antena + " Tipo: " + etiqueta.tipo);
                                }
                            }
                        }
                    }

                    #endregion

                    #region ----IniciaConAntena3/4-----
                    if (tag.AntennaPortNumber.Equals(Constantes.ANTENNA3) |
                        tag.AntennaPortNumber.Equals(Constantes.ANTENNA4))
                    {
                        //Variable que indica que encontró la etiqueta en la lista
                        Boolean bEncontroListaSalida = false;
                        foreach (Etiqueta etiquetaSalida in this.listaSalida)
                        {
                            //Pregunta si la etiqueta existe en listaSalida
                            if (etiquetaSalida.epc.Equals(etiqueta.epc))
                            {
                                bEncontroListaSalida = true;
                                break;
                            }
                        }
                        //Si encontro la etiqueta en la lista, entonces actualiza sus datos en la lista Salida temporal
                        if (bEncontroListaSalida)
                            this.listaSalidaTemporal = registroTemporal(etiqueta, this.listaSalidaTemporal, Constantes.TIPOFIN);
                        //Si NO existe en listaSalida, busca etiqueta en listaEntrada
                        else
                        {
                            Boolean bEncontroListaEntrada = false;
                            Boolean bEncontroListaEntradaMismaAntena = false;
                            foreach (Etiqueta etiquetaEntrada in this.listaEntrada)
                            {
                                //Pregunta si la etiqueta existe en listaEntrada
                                if (etiquetaEntrada.epc.Equals(etiqueta.epc))
                                {
                                    //Pregunta si la antena que lo encontró es 1/2 y si es regitro de Inicio
                                    if (etiquetaEntrada.tipo.Equals(Constantes.TIPOINICIO))
                                        if (etiquetaEntrada.antena.Equals(Constantes.ANTENNA1.ToString()) |
                                            etiquetaEntrada.antena.Equals(Constantes.ANTENNA2.ToString()))
                                        {
                                            //Registra que si lo encontró
                                            bEncontroListaEntrada = true;
                                        }
                                    //Pregunta si la antena que lo encontró es 3/4
                                    if (etiquetaEntrada.antena.Equals(Constantes.ANTENNA3.ToString()) |
                                        etiquetaEntrada.antena.Equals(Constantes.ANTENNA4.ToString()))
                                    {
                                        bEncontroListaEntradaMismaAntena = true;
                                    }
                                }
                            }
                            //Encontró el Inicio de la lectura en la cola de entrada de la antena 1/2
                            if (bEncontroListaEntrada)
                            {
                                //Encontró al menos un registro en la lista de entrada con la antena 3/4
                                if (bEncontroListaEntradaMismaAntena)
                                {
                                    //Como encontró un registro, 
                                    this.listaEntradaTemporal = registroTemporal(etiqueta, this.listaEntradaTemporal, Constantes.TIPOFIN);
                                }
                                //NO encontró ningún registro en la lista de entrada sobre la antena 3/4
                                else
                                {
                                    //Se recupera la última etiqueta leída de listaEntradaTemporal
                                    foreach (Etiqueta etiquetaAMover in this.listaEntradaTemporal)
                                    {
                                        //Solo se debe validar que sea de la antena 1/2 porque el registro siempre es el último
                                        if (etiquetaAMover.epc.Equals(etiqueta.epc) &&
                                            (etiquetaAMover.antena.Equals(Constantes.ANTENNA1.ToString()) |
                                             etiquetaAMover.antena.Equals(Constantes.ANTENNA2.ToString())))
                                        {
                                            //Crea los datos de la etiqueta que se va a mover en una variable en memoria aparte
                                            Etiqueta etiquetaTemporal = new Etiqueta();
                                            etiquetaTemporal.antena = etiquetaAMover.antena;
                                            etiquetaTemporal.epc = etiquetaAMover.epc;
                                            etiquetaTemporal.fechaInicio = etiquetaAMover.fechaInicio;
                                            etiquetaTemporal.fechaFinal = etiquetaAMover.fechaFinal;
                                            etiquetaTemporal.tipo = Constantes.TIPOFIN;

                                            //Se graban la etiqueta temporal en Lista Entrada
                                            this.listaEntrada.Add(etiquetaTemporal);
                                            if (log.IsDebugEnabled)
                                            {
                                                log.Debug("Registro en Cola de Salida:" + etiquetaTemporal.epc + " Antena: " + etiquetaTemporal.antena + " Tipo: " + etiquetaTemporal.tipo);
                                            }
                                            //Se retira la etiqueta de la lista Entrada Temporal
                                            this.listaEntradaTemporal.Remove(etiquetaAMover);
                                            //Sale de la lista
                                            break;
                                        }
                                    }
                                    //Graba etiqueta en lista Salida con Antena 3/4 pero con indicador de Inicio
                                    etiqueta.tipo = Constantes.TIPOINICIO;
                                    this.listaEntrada.Add(etiqueta);
                                    if (log.IsDebugEnabled)
                                    {
                                        log.Debug("Registro en Cola de Entrada:" + etiqueta.epc + " Antena: " + etiqueta.antena + " Tipo: " + etiqueta.tipo);
                                    }
                                }
                            }
                            //NO Encontró registro en la lista de Salida
                            else
                            {
                                //Se agrega el indicador que es el primer registro y se graba como inicio
                                etiqueta.tipo = Constantes.TIPOINICIO;
                                //Se agrega en la LISTA SALIDA
                                this.listaSalida.Add(etiqueta);
                                if (log.IsDebugEnabled)
                                {
                                    log.Debug("Registro en Cola de Salida:" + etiqueta.epc + " Antena: " + etiqueta.antena + " Tipo: " + etiqueta.tipo);
                                }
                            }
                        }
                    }

                    #endregion


                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
            }
        }

        #endregion

        #region --- Eventos del Personalizados ---

        private bool validarTiempoLimpiar(DateTime tiempoLecturaRegistrado)
        {
            TimeSpan tiempoDiferencia = DateTime.Now - tiempoLecturaRegistrado;
            int tiempoEsperaLectura = 0;

            tiempoEsperaLectura = Convert.ToInt32(ConfigurationManager.AppSettings[Constantes.LLAVE_TIEMPO_LIMPIA_LISTA]);

            return tiempoDiferencia.Minutes >= tiempoEsperaLectura;
        }

        private bool validarTiempoLectura(DateTime tiempoLecturaRegistrado)
        {
            TimeSpan tiempoDiferencia = DateTime.Now - tiempoLecturaRegistrado;
            int tiempoEsperaLectura = 0;

            tiempoEsperaLectura = Convert.ToInt32(ConfigurationManager.AppSettings[Constantes.LLAVE_TIEMPO_ESPERA_LECTURA]);

            return tiempoDiferencia.Minutes >= tiempoEsperaLectura;
        }

        private bool esEtiquetaValida(string epc)
        {
            epc = epc.Trim();
            if (epc.Length.Equals(29))
            {
                string cabecera = epc.Substring(0, 16);
                return cabecera.Equals(this.IDENTIFICADOR_CAB_ETIQUETA);
            }
            else
                return false;
        }

        static List<Etiqueta> registroTemporal(Etiqueta etiqueta, List<Etiqueta> listaTemporal, String tipo)
        {
            List<Etiqueta> ListaEtiquetaAyuda = new List<Etiqueta>();
            etiqueta.tipo = tipo;

            foreach (Etiqueta etiquetaLeida in listaTemporal)
            {
                //Si la etiqueta existe en la lista temporal, se retira
                if (!etiquetaLeida.epc.Equals(etiqueta.epc))
                {
                    ListaEtiquetaAyuda.Add(etiquetaLeida);
                }
            }
            //Siempre se agrega la etiqueta en Etiqueta Ayuda por que ha sido retirada y se agrega con nuevos datos
            ListaEtiquetaAyuda.Add(etiqueta);
            return ListaEtiquetaAyuda;
        }
        #endregion
    }
}
